package co.yixiang.modules.system.util;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.ClassUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import co.yixiang.modules.system.annotation.DictAnno;
import co.yixiang.modules.system.domain.DictDetail;
import co.yixiang.modules.system.service.DictDetailService;
import co.yixiang.modules.system.dto.queryCriteria.DictDetailQueryCriteria;
import com.baomidou.mybatisplus.core.toolkit.StringPool;
import com.google.common.collect.Maps;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cglib.beans.BeanMap;
import org.springframework.stereotype.Component;

import java.lang.reflect.Field;
import java.util.*;
import java.util.Map.Entry;
import java.util.stream.Collectors;

@Component
@Slf4j
public class DictUtils {

	public static final String MULTIPLE = "_multiple";

	private static DictDetailService dictDetailService;

	@Autowired
	public DictUtils(DictDetailService dictDetailService) {
		DictUtils.dictDetailService = dictDetailService;
	}

	/**
	 * 字典转换
	 * @param data 要转换的数据
	 * @param params 要转换的参数, Map类型, key为对象属性名, 若是多重转换则在属性名后加常量MULTIPLE (","分隔的数据全部转换, 例: 字典为 1->0 , 11 -> 22, 属性转换 "1,11" -> "0,22" ) ; value 为字典类型
	 * @return 转换后的数据, 原属性不动,字典属性名为在原属性名后加"xxx_text", 多重转换属性为 "xxx_multiple_text"
	 */
	public static List<Map> dictConvert(List<Map> data, Map<String, String> params) {

		// 参数的字典集合
		Map<String, List<DictDetail>> paramEntries = params.entrySet().stream().collect(Collectors.toMap(Entry::getKey, o -> findByDictType(o.getValue())));

		return data.stream().map(o -> setDataVal(params, paramEntries, o)).collect(Collectors.toList());
	}

	/**
	 * 字典转换
	 * @param data 要转换的数据
	 * @param params 要转换的参数, Map类型, key为对象属性名, 若是多重转换则在属性名后加常量MULTIPLE (","分隔的数据全部转换, 例: 字典为 1->0 , 11 -> 22, 属性转换 "1,11" -> "0,22" ) ; value 为字典类型
	 * @return 转换后的数据, 原属性不动,字典属性名为在原属性名后加"xxx_text", 多重转换属性为 "xxx_multiple_text"
	 */
	public static Map dictConvert(Map data, Map<String, String> params) {
		// 参数的字典集合
		Map<String, List<DictDetail>> paramEntries = params.entrySet().stream().collect(Collectors.toMap(Entry::getKey, o -> findByDictType(o.getValue())));

		return setDataVal(params, paramEntries, data);
	}

	/**
	 * 字典转换 转换数据 xxx 属性 需要有xxx_text属性
	 * @param data 要转换的数据
	 * @param params 要转换的参数, Map类型, key为对象属性名, 若是多重转换则在属性名后加常量MULTIPLE (","分隔的数据全部转换, 例: 字典为 1->0 , 11 -> 22, 属性转换 "1,11" -> "0,22" ) ; value 为字典类型
	 * @return 转换后的数据, 原属性不动,字典属性名为在原属性名后加"xxx_text", 多重转换属性为 "xxx_multiple_text"
	 */
	public static <T> List<T> dictConvertBean(List<T> data, Map<String, String> params) {
		if (data == null || data.isEmpty()) {
			return data;
		}

		T arg = data.get(0);
		Class<T> tClass = (Class<T>) arg.getClass();

		List<Map> mapList = data.stream().map(BeanMap::create).collect(Collectors.toList());

		// 参数的字典集合
		Map<String, List<DictDetail>> paramEntries = params.entrySet().stream().collect(Collectors.toMap(Entry::getKey, o -> findByDictType(o.getValue())));
		List<Map> collect = mapList.stream().map(o -> setDataVal(params, paramEntries, o)).collect(Collectors.toList());
		return collect.stream().map(o -> BeanUtil.mapToBean(o, tClass, false)).collect(Collectors.toList());
	}

	/**
	 * 字典转换 转换数据 xxx 属性 需要有xxx_text属性
	 * @param data 要转换的数据 (要转换的数据中需要有DictAnno注解)
	 * @return 转换后的数据, 原属性不动,字典属性名为在原属性名后加"xxx_text"
	 */
	public static <T> List<T> dictConvertBean(List<T> data) {
		if (data == null || data.isEmpty()) {
			return data;
		}

		T arg = data.get(0);

		Class<T> tClass = ClassUtil.getClass(arg);

		Field[] objFields = tClass.getDeclaredFields();

		Map<String, List<DictDetail>> dictMap = Arrays.stream(objFields)
				.filter(item -> {
					DictAnno annotation = item.getAnnotation(DictAnno.class);
					return ObjectUtil.isNotNull(annotation) && StrUtil.isNotBlank(annotation.value());
				})
				.map(item -> item.getAnnotation(DictAnno.class).value())
				.collect(Collectors.toMap(o -> o, DictUtils::findByDictType));

		// 参数的字典集合
		return data.stream().map(o -> setDataValByAnno(o, tClass, dictMap)).collect(Collectors.toList());
	}

	/**
	 * 字典转换 转换数据 xxx 属性 需要有xxx_text属性
	 * @param data 要转换的数据 (要转换的数据中需要有DictAnno注解)
	 * @return 转换后的数据, 原属性不动,字典属性名为在原属性名后加"xxx_text"
	 */
	public static <T> T dictConvertBean(T data) {
		if (data == null) {
			return null;
		}

		Class<T> tClass = ClassUtil.getClass(data);

		return setDataValByAnno(data, tClass, null);
	}

	/**
	 * 字典转换
	 * @param data 要转换的数据
	 * @param params 要转换的参数, Map类型, key为对象属性名, 若是多重转换则在属性名后加常量MULTIPLE (","分隔的数据全部转换, 例: 字典为 1->0 , 11 -> 22, 属性转换 "1,11" -> "0,22" ) ; value 为字典类型
	 * @return 转换后的数据, 原属性不动,字典属性名为在原属性名后加"xxx_text", 多重转换属性为 "xxx_multiple_text"
	 */
	public static List<Map> dictConvert(Map<String, String> params, List<?> data) {

		List<Map> mapList = data.stream().map(BeanMap::create).collect(Collectors.toList());

		return dictConvert(mapList, params);
	}

	private static Map setDataVal(Map<String, String> params, Map<String, List<DictDetail>> paramEntries, Map data) {
		Map temp = Maps.newHashMap(data);
		params.forEach((key, val) -> {
			// 判断是否是逗号分隔的多重字典转换属性, 并获取值
			boolean isMultiple = key.endsWith(MULTIPLE);
			String newKey = key.replace(MULTIPLE, "");
			Object obj = data.get(newKey);

			// 字典只转换字符串类型
			if (obj instanceof String) {
				String value = (String) obj;

				if (StringUtils.isNotBlank(value)) {
					// 获取需要转换的属性集合
					String convert = getDictConvertResult(isMultiple, paramEntries.get(key), value);

					if (StringUtils.isNotBlank(convert)) {
						temp.put(newKey + "_text", convert);
					}
				}
			}
		});
		return temp;
	}

	private static <T> T setDataValByAnno(T data, Class<T> clazz, Map<String, List<DictDetail>> dictMap) {
		Field[] objFields = clazz.getDeclaredFields();
		Arrays.stream(objFields).forEach(item -> {
			DictAnno dictAnno = item.getAnnotation(DictAnno.class);
			if (dictAnno == null) {
				return;
			}
			String dictType = dictAnno.value();
			if (StringUtils.isBlank(dictType)) {
				return;
			}

			// 转换属性字典集合
			List<DictDetail> dictDetailList = ObjectUtil.isNotEmpty(dictMap) ? dictMap.get(dictType) : DictUtils.findByDictType(dictType);

			String fieldName = item.getName();
			Object fieldValue = BeanUtil.getFieldValue(data, fieldName);

			if (ObjectUtil.isNull(fieldValue)) {
				return;
			}
			String fieldValueStr = fieldValue.toString();

			String value = getDictConvertResult(dictAnno.multiple(), dictDetailList, fieldValueStr);

			if (StringUtils.isBlank(value)) {
				return;
			}

			String newFieldName = fieldName + "_text";

			BeanUtil.setFieldValue(data, newFieldName, value);

		});

		return data;
	}

	/**
	 * 获取转换结果
	 * @param multiple 是否逗号分隔多重转换
	 * @param dictDetailList 字典集合
	 * @param oldValStr 数据值
	 * @return 转换结果
	 */
	private static String getDictConvertResult(boolean multiple, List<DictDetail> dictDetailList, String oldValStr) {
		// 获取需要转换的属性集合
		Set<String> waitingConvert = new HashSet<>();
		if (multiple) {
			waitingConvert.addAll(Arrays.asList(oldValStr.split(StringPool.COMMA)));
		} else {
			waitingConvert.add(oldValStr);
		}

		// 获取需转换属性的转换结果
		return dictDetailList.stream().filter(detail -> waitingConvert.contains(detail.getValue())).map(DictDetail::getLabel).collect(Collectors.joining(StringPool.COMMA));
	}

	/**
	 * 根据字典类型获取字典详情
	 * @param dictName 字典类型
	 * @return 字典详情数据
	 */
	public static List<DictDetail> findByDictType(String dictName){
		DictDetailQueryCriteria build = DictDetailQueryCriteria.builder().dictName(dictName).build();
		return dictDetailService.queryAll(build);
	}

}
